iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
1

終於要開始實作「獲取用戶地理位置」的功能了/images/emoticon/emoticon12.gif

要獲取地理位置必須使用「Geolocation API」這個Web API。先來看一下這個API的瀏覽器支援程度:

整體來說還算不錯,有9成的browser覆蓋率XDD

了解如何使用這個API前,要先在feed.js中來存取前端頁面的「目前所在地按鈕」和「等待圖示」。並在feed.css中將等待圖示預設為隱藏

var locationBtn = document.querySelector('#location-btn');
var locationLoader = document.querySelector('#location-loader');
var fetchedLocation;   // 透過Geolocation API取得的「經緯度」放在此變數中
#create-post #location-loader {
  display: none;
}

當用戶開啟發佈貼文頁面時,在openCreatePostModal() function中,新增initializeLocation()函式。初始化函式只是先確認瀏覽器有無支援Geolocation API,沒有的話就將「目前所在地按鈕」隱藏起來:

function initializeLocation() {
  if(!('geolocation' in navigator)) {
    locationBtn.style.display = 'none';
  }
}

而當用戶關閉發佈貼文頁面時,就在closeCreatePostModal() function中將「目前所在地按鈕」和「等待圖示」恢復預設值:

locationBtn.style.display = 'inline';
locationLoader.style.display = 'none';

接著要來開始實作用戶點擊「目前所在地按鈕」後,取得地理位置的功能:

locationBtn.addEventListener('click', function(event) {
  var sawAlert = false;   // 這裡是為了避免alert警告跳出兩次
  locationBtn.style.display = 'none';
  locationLoader.style.display = 'block';

  navigator.geolocation.getCurrentPosition(function(position) {
    locationBtn.style.display = 'inline';
    locationLoader.style.display = 'none';
    fetchedLocation = {
      lat: position.coords.latitude,
      lng: position.coords.longitude
    };
    fetch('https://api.opencagedata.com/geocode/v1/json?key=edc4d63b87574763be46eb988e85172c&q=' + fetchedLocation.lat + '%2C+' + fetchedLocation.lng + '&pretty=1&no_annotations=1').then(function(res) {
      return res.json();
    }).then(function(data) {
      console.log(data);
      locationInput.value = data.results[0].components.county;
      document.querySelector('#manual-location').classList.add('is-focused');
    });
  }, function(err) {
    console.log(err);
    locationBtn.style.display = 'inline';
    locationLoader.style.display = 'none';
    if(!sawAlert) {
      sawAlert = true;
      alert('無法獲取用戶位置,請手動輸入!!');
    }
    fetchedLocation = {
      'lng': 0,
      'lat': 0
    };
  }, {timeout: 7000})
});

首先,在監聽到用戶點擊「目前所在地按鈕」的事件後,先將按鈕隱藏起來,並顯示等待圖示。接著使用geolocation.getCurrentPosition()方法取得用戶目前所在的地理位置,方法中要輸入「2個callback function」和「1個option object」。第一個為成功接收到用戶position(經緯度)時的success callback function,第二個為error callback function,最後的參數設定等待API回復的時間(這裡設成7秒)。

在第一個success callback function中,代表成功取得地理位置,所以再一次的按鈕顯示出來,並將等待圖示隱藏起來。接著使用position.coords將用戶的經緯度值傳到fetchedLocation object中。

由於這裡透過API取得到的只有經緯度資訊而已,為了要將「經緯度」轉換成「一般的地理位置」,我使用OpenCage Geocoder API。fetch回來的response data內容非常多,這裡我只使用data.results[0].components.county取得用戶所在的縣市,並把它顯示在location input欄位中。

至於第2個error callback function,也就是當無法取得location時,就將「目前所在地按鈕」和「等待圖示」恢復成預設,以及把fetchedLocation object中的經緯度設為0。


目前實作到這邊,PWA project的功能都已經完成的差不多了,不過還有兩個bug需要修復 XDD

第一個為當用戶關閉發佈貼文視窗時,攝像鏡頭還是繼續開啟的,所以必須在closeCreatePostModal() function中加入之前寫過的「停止video stream」的code:

if(videoPlayer.srcObject) {
    videoPlayer.srcObject.getVideoTracks().forEach(function(track) {
      track.stop();
    });
}

第二個為當用戶網路離線時,會發現背景同步時會出現錯誤,因為我還有去呼叫一個外部的OpenCage Geocoder API,而這邊必須要catch住這個error,以下為完整的fetch程式碼,可以發現catch中的code是直接copy上面已經寫好的error callback function

fetch('https://api.opencagedata.com/geocode/v1/json?key=edc4d63b87574763be46eb988e85172c&q=' + fetchedLocation.lat + '%2C+' + fetchedLocation.lng + '&pretty=1&no_annotations=1').then(function(res) {
      return res.json();
    }).then(function(data) {
      console.log(data);
      locationInput.value = data.results[0].components.county;
      document.querySelector('#manual-location').classList.add('is-focused');
    }).catch(function(err) {
      console.log(err);
      locationBtn.style.display = 'inline';
      locationLoader.style.display = 'none';
      if(!sawAlert) {
        sawAlert = true;
        alert('無法獲取用戶位置,請手動輸入!!');
      }
      fetchedLocation = {
        'lng': 0,
        'lat': 0
      };
});

呼!! 寫到這,PWA project該有的功能都已經完成的了~~~可喜可賀
Day27 結束!! /images/emoticon/emoticon02.gif


上一篇
[Day26] 了解Media API和Geolocation API(Part2)
下一篇
[Day28] 自動化管理Service Worker(Part1)
系列文
你應該要知道的新一代Web技術---漸進式網頁(PWA)29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言